#include <iostream>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "traffic_sim.h"

namespace Traffic_Sim 
{
	/////////  Random Generator
	void Random_Generator::initialize_rand_gen()
	{
		r = gsl_rng_alloc (gsl_rng_mt19937);
	  gsl_rng_set(r, time(NULL) % gsl_rng_max(r));
	}
	 
	double Random_Generator::get_uniform_rnd(double lower, double upper)
	{
	  double rnd = gsl_ran_flat(r, lower, upper);
	  return rnd;
	}
	
	unsigned long Random_Generator::get_random_int (long limit)
	{
	  return gsl_rng_uniform_int(r, limit);
	}
	
	double Random_Generator::get_exponential_rnd(double mean)
	{
	  double rnd = gsl_ran_exponential(r, mean);
	  return rnd;
	}
	
	double Random_Generator::get_normal_rnd (double mean, double std_dev)
	{
	  double rnd = gsl_ran_gaussian(r, std_dev);
	  rnd += mean;
	  return rnd;
	}
	
	unsigned int Random_Generator::get_poisson_rnd (double mean)
	{
	  return gsl_ran_poisson(r, mean);
	}
	
	
	///////////// Random Time
	void Random_Time::init(Time_Distribution dist, double param1, double param2)
	{
	  time_distribution = dist;
	  time_dist_param_1 = param1;
	  time_dist_param_2 = param2;
	}
	
	Random_Time::Random_Time() 
	{ 
	  init(Constant, 20, 0);
	}
	
	Random_Time::Random_Time(Time_Distribution dist, double param1) 
	{
	  init(dist, param1, 0);
	}
	
	Random_Time::Random_Time(Time_Distribution dist, double param1, double param2) 
	{
	  init(dist, param1, param2);
	}
	
	long Random_Time::get_time()
	{
	  double time_length;
	  switch (time_distribution)
	  {
	    case Constant :
	      time_length = time_dist_param_1;
	      break;
	    case Normal :
	      time_length = Random_Generator::get_instance()
          .get_normal_rnd(time_dist_param_1, time_dist_param_2);
	      break;
	    case Uniform :
	      time_length = Random_Generator::get_instance()
          .get_uniform_rnd(time_dist_param_1, time_dist_param_2);
	      break;
	    case Exponential :
	      time_length = Random_Generator::get_instance()
          .get_exponential_rnd(time_dist_param_1);
	      break;
	  }
	  return (long)time_length;
	}
	  
	///////// Traffic_Agent_Impl
	
	void Traffic_Agent_Impl::execute(Traffic_Agent * agent, Traffic_Graph * graph)
	{
		if (agent == NULL);
		if (graph == NULL);
	}
	
	Traffic_Agent_Impl::Traffic_Agent_Impl(int id, const string & desc) 
    : id(id), description(desc) { /* Empty */ }
  
  Traffic_Agent_Impl::~Traffic_Agent_Impl() {  }
	
	bool Traffic_Agent_Impl::operator == (const Traffic_Agent_Impl & otroAgente) const 
	{
	  return id == otroAgente.id;
	}
	
	void Traffic_Agent_Impl::update_graphics()
	{
		if (update_callback != NULL) 
		{
			update_callback(callback_cookie);
		}
	}
	
	int Traffic_Agent_Impl::get_id()
	{
	  return id;
	}
	
	string Traffic_Agent_Impl::get_description()
	{
	  return description;
	}
	
	const Traffic_Agent & Traffic_Agent_Impl::get_agent() const
	{
		return (*agent);
	}
	
	void Traffic_Agent_Impl::set_update_callback(Update_Callback callback, void * cookie)
	{
	  update_callback = callback;
	  callback_cookie = cookie;
	}
		
	void Traffic_Agent_Impl::traffic_agent_execution(void * graph_ptr, void * agent_ptr)
	{
	  Traffic_Agent * agent = static_cast<Traffic_Agent *>(agent_ptr);
	  Traffic_Graph * graph = static_cast<Traffic_Graph *>(graph_ptr);
	  agent->get_info()->execute(agent, graph);
	}
	
	void Traffic_Agent_Impl::create_agent_in_node(Traffic_Agent_Impl * agent, 
    Traffic_Graph * graph, Traffic_Node * node, long activation_time)
	{
	  Traffic_Agent * sim_agent = graph->create_agent_in_node(agent, 
      &Traffic_Agent_Impl::traffic_agent_execution, node, activation_time);
	  agent->agent = sim_agent; 
	}
	
	void Traffic_Agent_Impl::create_agent_in_arc(Traffic_Agent_Impl * agent, 
    Traffic_Graph * graph, Traffic_Arc * arc, long activation_time)
	{
	  Traffic_Agent * sim_agent = graph->create_agent_in_arc(agent, 
      &Traffic_Agent_Impl::traffic_agent_execution, arc,activation_time);
	  agent->agent = sim_agent; 
	}
	
	///////////// Traffic_Node_Departure_Event
	
   Traffic_Node_Departure_Event::Traffic_Node_Departure_Event(Traffic_Agent * _agent, 
    Traffic_Node * _from_node, Traffic_Arc * _to_arc, long time)
    : Sim_Event(time), agent(_agent), from_node(_from_node), to_arc(_to_arc) { }
  Traffic_Node_Departure_Event::~Traffic_Node_Departure_Event() { }
	
	
	void Traffic_Node_Departure_Event::execute_event(void * graph_ptr)
	{
	  Traffic_Graph * graph = static_cast<Traffic_Graph *> (graph_ptr);
	  Traffic_Vehicle * vehicle = static_cast<Traffic_Vehicle *>(agent->get_info());
	  agent->actual_time = actual_time;
	  vehicle->notify_node_departure(graph, agent, from_node, to_arc);
	  Sim_Event::to_be_destroyed = true;
	}
	
	//////////// Traffic_Node_Arrival_Event
	
  Traffic_Node_Arrival_Event::Traffic_Node_Arrival_Event(Traffic_Agent * _agent, 
    Traffic_Node * _to_node, Traffic_Arc * _from_arc, long time)
    : Sim_Event(time), agent(_agent), to_node(_to_node), from_arc(_from_arc) { }
  Traffic_Node_Arrival_Event::~Traffic_Node_Arrival_Event() { }
	
	
	void Traffic_Node_Arrival_Event::execute_event(void * graph_ptr)
	{
	  Traffic_Graph * graph = static_cast<Traffic_Graph *> (graph_ptr);
	  Traffic_Vehicle * vehicle = static_cast<Traffic_Vehicle *>(agent->get_info());
	 	agent->actual_time = actual_time;
	  vehicle->notify_node_arrival(graph, agent, to_node, from_arc);
	  Sim_Event::to_be_destroyed = true;
	}
	
	
	//////////// Traffic_Agent_Destruction_Event
	
  Traffic_Agent_Destruction_Event::Traffic_Agent_Destruction_Event(Traffic_Agent * _agent, 
    long time) : Sim_Event(time), agent(_agent) {  }

  Traffic_Agent_Destruction_Event::~Traffic_Agent_Destruction_Event() { }
	
	void Traffic_Agent_Destruction_Event::execute_event(void * graph_ptr)
	{
	  Traffic_Graph * graph = static_cast<Traffic_Graph *> (graph_ptr);
	  Traffic_Vehicle * vehicle = dynamic_cast<Traffic_Vehicle *>(agent->get_info());
	  agent->actual_time = actual_time;
	  if (vehicle != NULL)
	  {
	  	vehicle->notify_agent_destruction();
	  }
	  graph->remove_agent(agent);
    to_be_destroyed = true;
	}
  
  //////////// Traffic_Semaphore_Check_Event
  
  Traffic_Semaphore_Check_Event::Traffic_Semaphore_Check_Event(Traffic_Agent * _agent, 
        Traffic_Node * _in_node, Traffic_Arc * _from_arc, Traffic_Arc * _to_arc, long time) 
        : Sim_Event(time), agent(_agent), in_node(_in_node), from_arc(_from_arc), 
          to_arc(_to_arc) { }
  
  Traffic_Semaphore_Check_Event::~Traffic_Semaphore_Check_Event() { }
  
  void Traffic_Semaphore_Check_Event::execute_event(void * graph_ptr)
  {
    Traffic_Graph * graph = static_cast<Traffic_Graph *> (graph_ptr);
    Traffic_Vehicle * vehicle = static_cast<Traffic_Vehicle *>(agent->get_info());
    agent->actual_time = actual_time;
    vehicle->notify_semaphore_check(graph, agent, in_node, from_arc, to_arc);
    Sim_Event::to_be_destroyed = true;    
  }

	//////////// Traffic_Vehicle
	
	Traffic_Vehicle::Traffic_Vehicle(int id, const string & desc) : Traffic_Agent_Impl(id, desc) 
	{
		waiting_destruction = false;  
    waiting_for_semaphore = false;
    previous_node = NULL;
	}
	
  Traffic_Vehicle::~Traffic_Vehicle() { }
		
  Vehicle_Event_Type Traffic_Vehicle::get_last_event()
  {
    return last_event;
  }
  
  bool Traffic_Vehicle::is_waiting_destruction()
  {
    return waiting_destruction;
  }
  
  bool Traffic_Vehicle::is_waiting_for_semaphore()
  {
    return waiting_for_semaphore;
  }

	void Traffic_Vehicle::execute(Traffic_Agent * agent, Traffic_Graph * graph)
	{
	  long schedule_time = agent->actual_time;
	  last_event = Agent_Creation;
	  if (agent->in_node)
	  {
	    //Proximo evento: Node Departure
	    Traffic_Node * from_node = graph->get_agent_node_location(agent);
	    Arc_Set * empty_set = NULL;
	    Traffic_Arc * to_arc = choose_next_arc(graph, from_node, empty_set);
	    if (to_arc != NULL) {
 	      schedule_time += DELAY_TIME_IN_NODES;
	      Traffic_Node_Departure_Event * next_event = 
          new Traffic_Node_Departure_Event(agent,  from_node, to_arc, schedule_time);
	      graph->schedule_event(next_event);
	    } else {
	      Traffic_Agent_Destruction_Event * next_event = 
          new Traffic_Agent_Destruction_Event(agent, agent->actual_time + 1);
	      graph->schedule_event(next_event);
	    }
	  } 
	  else
	  {
	    //Proximo evento: Node Arrival
	      Traffic_Arc * from_arc = graph->get_agent_arc_location(agent);
	      Traffic_Node * to_node = choose_initial_direction(graph, from_arc);
	      schedule_time += from_arc->get_info().get_delay_time();
	      Traffic_Node_Arrival_Event * next_event = 
          new Traffic_Node_Arrival_Event(agent, to_node, from_arc, schedule_time);
	      graph->schedule_event(next_event);
	  }
	  update_graphics();
	}
	
	Traffic_Node * Traffic_Vehicle::choose_initial_direction(Traffic_Graph * graph, 
    Traffic_Arc * initial_arc)
	{
	  return graph->get_tgt_node(initial_arc);
	}
	
	Traffic_Arc * Traffic_Vehicle::choose_next_arc(Traffic_Graph * graph, 
    Traffic_Node * current_node, Arc_Set * exclusion_set)
	{
	  Traffic_Arc * result = NULL;
	  if (graph == NULL);
	  Traffic_Graph::Node_Arc_Iterator itor(current_node);
	  do {
	    if (itor.has_current())
	    {
	       result = itor.get_current_arc();
	    } else {
	      break;
	    }
	    if (exclusion_set != NULL){
	      if (exclusion_set->count(result->get_info().description) == 1)
	      {
	        result = NULL;
	      }
	    }
	    itor.next();
	  } while (result == NULL);
	  return result;
	}
	
	
	void Traffic_Vehicle::notify_node_arrival(Traffic_Graph * graph, 
    Traffic_Agent * agent, Traffic_Node * to_node, Traffic_Arc * from_arc)
	{
	  long schedule_time = agent->actual_time;
	  graph->set_agent_node_location(agent, to_node);
	  last_event = Node_Arrival;
	  Traffic_Node * from_node = to_node;
    Arc_Set * exclusion_set = new Arc_Set();
    exclusion_set->insert(from_arc->get_info().description);
    Traffic_Arc * to_arc = choose_next_arc(graph, from_node, exclusion_set);
    bool semaphore_ok = true;
    if (to_node->get_info().semaphore != NULL && to_arc != NULL)
    {
      // Hay semaforo, observar el color
      Semaphore_Color color = to_node->get_info().semaphore->get_color(from_arc, 
        to_arc);
      if (color == Red)
      {
        semaphore_ok = false;
      }
    }
    if (semaphore_ok)
    {
      waiting_for_semaphore = false;
	    if (to_arc == NULL)
	    {
	      Traffic_Agent_Destruction_Event * event = 
          new Traffic_Agent_Destruction_Event(agent, agent->actual_time + 1);
	      graph->schedule_event(event);
	      waiting_destruction = true;
	    } 
	    else
	    {
	      schedule_time += DELAY_TIME_IN_NODES;
		    Traffic_Node_Departure_Event * next_event = 
          new Traffic_Node_Departure_Event(agent,  from_node, to_arc, schedule_time);
		    graph->schedule_event(next_event);
		  }
    } else {
      // Se programa un evento para revisión del semáforo, en t + 1
      Traffic_Semaphore_Check_Event * next_event = 
        new Traffic_Semaphore_Check_Event(agent, from_node, from_arc, to_arc, 
            agent->actual_time + 1);
        waiting_for_semaphore = true; 
        graph->schedule_event(next_event);
    }
	  update_graphics();
	}
	
	void Traffic_Vehicle::notify_node_departure(Traffic_Graph * graph, 
    Traffic_Agent * agent, Traffic_Node * from_node, Traffic_Arc * to_arc)
	{
    long schedule_time = agent->actual_time;
    graph->set_agent_arc_location(agent, to_arc);
    last_event = Node_Departure;
    Traffic_Arc * from_arc = to_arc;
    //Actualizar el nodo previo
    previous_node = from_node;
    Traffic_Node * to_node = graph->get_connected_node(to_arc, from_node);
    schedule_time += from_arc->get_info().get_delay_time();
    Traffic_Node_Arrival_Event * next_event = 
      new Traffic_Node_Arrival_Event(agent, to_node, from_arc, schedule_time);
    graph->schedule_event(next_event);
    update_graphics();
	}
	
	void Traffic_Vehicle::notify_agent_destruction()
	{
		last_event = Agent_Destruction;
		update_graphics();
	}

  void Traffic_Vehicle::notify_semaphore_check(Traffic_Graph * graph, 
          Traffic_Agent * agent, Traffic_Node * in_node, Traffic_Arc * from_arc, 
          Traffic_Arc * to_arc)
  {
    //Observar el color
    Semaphore_Color color = in_node->get_info().semaphore->get_color(from_arc, 
      to_arc);
    if (color == Red)
    {
      // Aun no cambia el color, volver a programar el evento
      Traffic_Semaphore_Check_Event * next_event = 
        new Traffic_Semaphore_Check_Event(agent, in_node, from_arc, to_arc, 
            agent->actual_time + 1);
        waiting_for_semaphore = true; 
        graph->schedule_event(next_event);      
    } 
    else
    {
      // Cambio el semaforo, planificar el abandono del nodo
      Traffic_Node_Departure_Event * next_event = 
        new Traffic_Node_Departure_Event(agent, in_node, to_arc, 
          agent->actual_time + 1);
      waiting_for_semaphore = false;
      graph->schedule_event(next_event);      
    }
    update_graphics();
  }
	///////////// Traffic_Random_Vehicle
	
	Traffic_Random_Vehicle::Traffic_Random_Vehicle(int id, const string & desc) 
    : Traffic_Vehicle(id, desc) { }
	
  Traffic_Random_Vehicle::~Traffic_Random_Vehicle() { }
		
  Traffic_Node * Traffic_Random_Vehicle::choose_initial_direction(
    Traffic_Graph * graph, Traffic_Arc * initial_arc)
  {
    Traffic_Node * result = NULL;

    if (Random_Generator::get_instance().get_random_int(2) == 1)
    {
      result = graph->get_src_node(initial_arc);
    }
    else 
    {
      result = graph->get_tgt_node(initial_arc);
    }
    return result;
  }

  Traffic_Arc * Traffic_Random_Vehicle::choose_next_arc(Traffic_Graph * graph, 
    Traffic_Node * current_node, Arc_Set * exclusion_set)
  {
    Traffic_Arc * result = NULL;
    if (graph);
    // Extraer el conjunto diferencia
    DynDlist<Traffic_Arc*> remaining_arcs;
    int included_arcs = 0;
    for (Traffic_Graph::Node_Arc_Iterator itor(current_node); itor.has_current(); 
        itor.next())
    {
      Traffic_Arc * arc = itor.get_current_arc();
      if (exclusion_set != NULL){
        if (exclusion_set->count(arc->get_info().description) == 0)
        {
          remaining_arcs.insert(arc);
          included_arcs++;
        }
      } else {
        remaining_arcs.insert(arc);
        included_arcs++;
      }
      
    }
    unsigned int selected = Random_Generator::get_instance()
      .get_random_int(included_arcs);
    unsigned int current = 0;
    for (DynDlist<Traffic_Arc*>::Iterator itor(remaining_arcs); 
        itor.has_current(); itor.next())
    {
      if (current == selected) {
        result = itor.get_current();
        break;
      }
      current++;
    }
    return result;
  }  
  ///////////// Traffic_Searching_Vehicle
  Traffic_Searching_Vehicle::Traffic_Searching_Vehicle(int id, const string & desc, 
    Traffic_Node * destination) : Traffic_Random_Vehicle(id, desc), 
    destination_node(destination) { }
  
  Traffic_Searching_Vehicle::~Traffic_Searching_Vehicle() { }
  
	void Traffic_Searching_Vehicle::notify_node_arrival(Traffic_Graph * graph, 
    Traffic_Agent * agent, Traffic_Node * to_node, Traffic_Arc * from_arc)
  {
    if (to_node == destination_node)
    {
      graph->set_agent_node_location(agent, to_node);
      // La meta fue lograda, se planifica la destrucción
      Traffic_Agent_Destruction_Event * next_event = 
        new Traffic_Agent_Destruction_Event(agent, agent->actual_time + 1);
      graph->schedule_event(next_event);
    } 
    else 
    {
      Traffic_Vehicle::notify_node_arrival(graph, agent, to_node, from_arc);
    }
  }

	////////////// Traffic_Semaphore
  
  int Traffic_Semaphore::get_arc_count()
  {
    return arc_count;
  }
  
  Traffic_Arc * Traffic_Semaphore::get_arc(int index) 
  {
    return arc_index_table[index];
  }
  
  
  Semaphore_Color Traffic_Semaphore::get_color_state(int arc_from, int arc_to)
  {
    Semaphore_Color result = Red;
    Semaphore_Color positive_color = Green;
     if (current_state % 3 == 1)
    {
      positive_color = Yellow;
    }
    if (current_state % 3 != 2 && arc_to != (arc_from + 3) % 4)
    {
      if (current_state == 3 || current_state == 4)
      {
        if (arc_from % 2 == 0)
        {
          result = positive_color;
        }
      } 
      else
      {
        if (arc_from % 2 == 1)
        {
          result = positive_color;
        }
      }
    } 
    else if (current_state % 3 == 2)
    {
      int sum = (arc_to + arc_from) % 4;
      if (sum % 2 == 1)
      {
        if ((current_state == 2 && sum == 1) || (current_state == 5 && sum == 3))
        {
          result = positive_color;
        } 
      }
    }
    return result;
  }

  long Traffic_Semaphore::get_next_change_delay()
  {
    int state_type = current_state % 3;
    long result = 5;
    if (state_type == 1)
    {
      result = 5;
    } else if (state_type == 2)
    {
      result = 5;
    }
    return result;
  }

  void Traffic_Semaphore::execute(Traffic_Agent * agent, Traffic_Graph * graph)
  {
    current_state = (current_state + 1) % states_count;
    agent->actual_time += get_next_change_delay();
    graph->schedule_event(agent);
    update_graphics();
  }

  Traffic_Semaphore::Traffic_Semaphore (int id, const string & desc, 
    Traffic_Node * parent, int _arc_count) : Traffic_Agent_Impl(id, desc), 
    parent_node(parent)
  {
    current_state = 0;
    states_count = 6;
    arc_count = _arc_count;
    arc_index_table = new Traffic_Arc*[arc_count];
  }

  Traffic_Semaphore::~Traffic_Semaphore() { }

  void Traffic_Semaphore::set_arc_index(Traffic_Arc * arc, int index)
  {
    arc_index_table[index] = arc;
  }

  int Traffic_Semaphore::find_arc_index(Traffic_Arc * arc)
  {
    int result = -1;
    for (int i = 0; i < arc_count; i++)
    {
      if (arc_index_table[i] == arc)
      {
        result = i;
        break;
      }
    }
    return result;
  }

  Semaphore_Color Traffic_Semaphore::get_color (Traffic_Arc * arc_from, 
    Traffic_Arc * arc_to)
  {
    int index_from = find_arc_index(arc_from); 
    int index_to = find_arc_index(arc_to);
    if ((index_from == -1) || (index_to == -1))
    {
      throw domain_error("Arco no válido usado en get_color()");
    }
    return get_color_state(index_from, index_to);
  }

  Semaphore_Color Traffic_Semaphore::get_color_to_show(int arc_index)
  {
    int arc_index_dest = (arc_index + 2) % 4;
    return get_color_state(arc_index, arc_index_dest);
  }
	 
	////////////// Three_Way_Traffic_Semaphore
  Semaphore_Color Three_Way_Traffic_Semaphore::get_color_state(int arc_from, 
    int arc_to)
  {
    long current_state = Traffic_Semaphore::current_state;
    Semaphore_Color result = Red;
    Semaphore_Color positive_color = Green;
    if (current_state == 2 || current_state == 4)
    {
      positive_color = Yellow;
    }
    if (current_state == 1 || current_state == 2)
    {
      if (arc_from + arc_to == 1)
      {
        result = positive_color;
      } 
      else if(arc_from == 1 && arc_to == 2)
      {
        result = Green;
      }
    }
    else
    {
      if (current_state == 0)
      {
        if ((arc_from + arc_to == 2) || (arc_from == 0 && arc_to == 1))
        {
          result = positive_color;
        }
      }
      else 
      {
        // estados 3 y 4
        if (arc_from + arc_to == 3) 
        {
          result = positive_color;
        }
        else if (arc_from == 2 && arc_to == 0)
        {
          result = Green;
        }
      }

    }
    return result;
  }

  long Three_Way_Traffic_Semaphore::get_next_change_delay()
  {
    long current_state = Traffic_Semaphore::current_state;
    if (current_state == 2 || current_state == 4)
    {
      return 5;
    } 
    else
    {
      return 5;
    }
  }

  Three_Way_Traffic_Semaphore::Three_Way_Traffic_Semaphore(int id, 
    const string & desc, Traffic_Node * parent, int _arc_count) 
    : Traffic_Semaphore(id, desc, parent, _arc_count)
  {
    Traffic_Semaphore::states_count = 5;
  }

  Three_Way_Traffic_Semaphore::~Three_Way_Traffic_Semaphore()
  {
  }

  Semaphore_Color Three_Way_Traffic_Semaphore::get_color_to_show(int arc_index)
  {
    int arc_index_dest =  1 - (arc_index % 2);
    return get_color_state(arc_index, arc_index_dest);
  }
	
	///////////// Traffic_Agent_Creation_Event
  bool Traffic_Agent_Creation_Event::keep_running()
  {
    bool result = false;
    time_t actual_time = time(NULL);
    double value;
    switch (source_mode)
    {
      case Sleep_Mode :
        if (actual_time - start_time < seconds_to_stop)
          result = true;
        break;
      case Count_Mode :
        if (it_count < iterations_to_stop)
          result = true;
        break;
      case Probabilistic_Mode :
        value = Random_Generator::get_instance().get_uniform_rnd(0, 100);
        result = (value < stop_probability);
        break;
      default:
        break;
    }
    return result;
  }

  Traffic_Agent_Creation_Event::Traffic_Agent_Creation_Event( 
    Create_Agent_Impl callback, Random_Time * _agent_time, long _time) 
    : Sim_Event(_time), create_agent_impl_callback(callback), agent_time(_agent_time) 
  {  
    source_mode = Reactive_Mode;
  }

  Traffic_Agent_Creation_Event::~Traffic_Agent_Creation_Event() { }
 
  Source_Mode Traffic_Agent_Creation_Event::get_mode()
  {
    return source_mode;
  }

  void Traffic_Agent_Creation_Event::set_mode(Source_Mode value)
  {
    source_mode = value;
  }

  long Traffic_Agent_Creation_Event::get_sleep_time()
  {
    return sleep_time;
  }

  void Traffic_Agent_Creation_Event::set_sleep_time(long value)
  {
    sleep_time = value;
  }

  long Traffic_Agent_Creation_Event::get_seconds_to_stop()
  {
    return seconds_to_stop;
  }

  void Traffic_Agent_Creation_Event::set_seconds_to_stop(long value)
  {
    seconds_to_stop = value;
  }

  long Traffic_Agent_Creation_Event::get_iterations_to_stop()
  {
    return iterations_to_stop;
  }

  void Traffic_Agent_Creation_Event::set_iterations_to_stop(long value)
  {
    iterations_to_stop = value;
  }

  double Traffic_Agent_Creation_Event::get_stop_probability()
  {
    return stop_probability;
  }

  void Traffic_Agent_Creation_Event::set_stop_probability(double value)
  {
    stop_probability = value;
  }

  double Traffic_Agent_Creation_Event::get_occurrence_mean()
  {
    return occurrence_mean;
  }

  void Traffic_Agent_Creation_Event::set_occurrence_mean(double value)
  {
    occurrence_mean = value;
  }

  Random_Time Traffic_Agent_Creation_Event::get_delay_time()
  {
    return delay_time;
  }
  
  void Traffic_Agent_Creation_Event::set_next_agent_id(long id)
  {
    next_agent_id = id;
  }
  
  long Traffic_Agent_Creation_Event::get_next_agent_id()
  {
    return next_agent_id;
  }

  void Traffic_Agent_Creation_Event::set_renderer_callback(Create_Renderer callback)
  {
    create_renderer_callback = callback;
  }
  
  void Traffic_Agent_Creation_Event::execute_event(void * graph_ptr) 
  {
    Traffic_Graph * graph = static_cast<Traffic_Graph *> (graph_ptr);
    void * location = NULL;
    unsigned int event_count = Random_Generator::get_instance()
      .get_poisson_rnd(occurrence_mean);
    for (unsigned int i = 0; i < event_count; i++)
    {
      // Checks if event type accepts location
	    bool in_node = Random_Generator::get_instance().get_random_int(2) == 0;
	    if (in_node)
	    {
	      // Select a node
	      int count = graph->get_num_nodes();
	      int selected = Random_Generator::get_instance().get_random_int(count);
	      int node_idx = 0;
	      for (Traffic_Graph::Node_Iterator node_it(*graph); node_it.has_current(); 
          node_it.next())
	      {
	        if (node_idx == selected)
	        {
	          location = node_it.get_current_node();
	          break;
	        }
	        else
	        {
	          node_idx++;
	        }
	      }
	    }
	    else
	    {
	      // Select an arc
	      int count = graph->get_num_arcs();
	      int selected = Random_Generator::get_instance().get_random_int(count);
	      int arc_idx = 0;
	      for (Traffic_Graph::Arc_Iterator arc_it(*graph); arc_it.has_current();
          arc_it.next())
	      {
	        if (arc_idx == selected)
	        {
	          location = arc_it.get_current_arc();
	          break;
	        }
	        else
	        {
	          arc_idx++;
	        }
	      }
	    }
      
      Traffic_Agent_Impl * new_agent_info = create_agent_impl_callback(next_agent_id++);
      if (create_renderer_callback != NULL)
      {
        create_renderer_callback(new_agent_info);
      }

	    if (in_node)
	    {
        Traffic_Agent_Impl::create_agent_in_node(new_agent_info, graph, 
          static_cast<Traffic_Node *>(location), agent_time->get_time());
	    } 
	    else 
	    {
	      Traffic_Agent_Impl::create_agent_in_arc(new_agent_info, graph, 
          static_cast<Traffic_Arc *>(location), agent_time->get_time());
	    }
	  } 
	  if (keep_running())
	  {
	    Sim_Event::actual_time += delay_time.get_time();
	    graph->schedule_event(this);
	  }
	  else 
	  {
	    Sim_Event::to_be_destroyed = true;
	  }
	}
	    
}
